
#ifdef WIN32
	//#include <windows.h>
	//#include <conio.h>
#else
	//Linux
	#include "unistd.h"
	#include <sys/select.h>

int _kbhit(void)
{
	struct timeval tv;
	fd_set read_fd;

	tv.tv_sec=0;
	tv.tv_usec=0;
	FD_ZERO(&read_fd);
	FD_SET(0,&read_fd);
	
	if(select(1, &read_fd, NULL, NULL, &tv) == -1)
		return 0;
	
	if(FD_ISSET(0,&read_fd))
		return 1;
	
	return 0;
}

#endif 

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "SmsPlatDefs.h"
#include "SmsCtrlLib.h"


void CtrlCallback(	void*						ClientContext,	//!< Context of client
					SMSHOSTLIB_MSG_TYPE_RES_E	MsgType,		//!< Response type	
					SMSHOSTLIB_ERR_CODES_E		ErrCode,		//!< Response success code
					void* 						pPayload,		//!< Response payload
					UINT32						PayloadLen);	//!< Response payload length

void DataCallback(void*		ClientPtr, 
				  UINT32	ServiceHandle, 
				  UINT8*	pBuffer, 
				  UINT32	BufferSize );


#define MAX_DEVICES		5
#define MAX_NETWORKS	5

// Hard coded data about the stream
#define STREAM_SERVICE_ID_TO_START (0x259)

SmsHostApiDeviceData_ST g_DeviceDataArr[MAX_DEVICES];
SMSHOSTLIB_CMMB_NETWORK_INFO_ST	g_NetworksInfoArr[MAX_NETWORKS];

//HANDLE g_MsgArrivedEvent;
BOOL g_DidMsgArrive = FALSE;
UINT32 g_WaitingForType;
SMSHOSTLIB_ERR_CODES_E g_WaitedErrCode;
char g_VersionString[256] = {0};
BOOL g_IsTerminated = FALSE;
UINT32 g_ControlInfoServiceHandle = 0;
UINT32 g_StartedServiceHandle = 0;
BOOL g_FoundGoodFreq = FALSE;


FILE* g_MultipklexFp;
FILE* g_ServiceFp;
UINT32 g_MpxCapturedSize = 0;
UINT32 g_ServiceCapturedSize = 0;

void MySleep( UINT32 ms )
{
#ifdef WIN32
	Sleep( ms );
#else
	usleep( ms*1000 );
#endif
}

SMSHOSTLIB_ERR_CODES_E WaitArrival( INT32 Milliseconds, UINT32 MsgType )
{
	g_WaitingForType = MsgType;
	while ( Milliseconds > 0 )
	{
		if ( g_DidMsgArrive )
		{
			g_DidMsgArrive = FALSE;
			return g_WaitedErrCode;
		}
		MySleep( 10 );
		Milliseconds -= 10;
	}
	return SMSHOSTLIB_ERR_TIMEOUT;
	
}

//extern "C" SMSHOSTLIB_ERR_CODES_E SMSHOSTLIB_API SmsHostSetDbgLogMask(UINT32 newDbgLogMask);

int wmain(int argc, char* argv[])
{
	SmsHostApiDeviceHandle	LocalDevHdl = (SmsHostApiDeviceHandle)~0;
	SMSHOSTLIB_ERR_CODES_E	err;
	UINT32 WaitTime = 0;
	UINT32 NumNetworks = 0;
	UINT32 Freq = (UINT32)550e6;
	INT32 Timeout = 0;

	//////////////////////////////////////////////////
	//
	// Open binary file for capturing data - in this example, it captures control info
	//
	g_MultipklexFp = fopen("sms_multiplex_capture.mfs","wb");
	if (!g_MultipklexFp) {
		printf("Error opening multiplex file\n");
		exit(1);
	}
	
	g_ServiceFp = fopen("sms_service_capture.bin","wb");
	if (!g_ServiceFp) {
		printf("Error opening service file\n");
		exit(1);
	}
	
	//////////////////////////////////////////////////
	//
	// Initialize an event for arrival of async messages
//	g_MsgArrivedEvent = Creg_MsgArrivedEventateEvent(NULL, FALSE, FALSE, NULL);

	//////////////////////////////////////////////////
	//
	// Initialize SMS Host Library

	SMSHOSTLIB_API_INITLIB_PARAMS_ST	InitLibSt;

	memset(&InitLibSt, 0, sizeof(InitLibSt));
	InitLibSt.Size		= sizeof(InitLibSt);
	InitLibSt.CommType	= SMSHOSTLIB_COMM_USB;
	InitLibSt.pCommParam = NULL;
	InitLibSt.WorkingDirectory = ".";
	InitLibSt.IsSupportMultInstances = TRUE ;
	InitLibSt.pCtrlCallback = CtrlCallback ;
	InitLibSt.pDataCallback = DataCallback ;

	printf( "Initializing library...\n" );
	err = SmsHostApiLibInit( &InitLibSt );

	if (err != SMSHOSTLIB_ERR_OK) {
		printf("SmsHostApiLibInit failed, err=%#x\n", err);
		goto exitapp;
	}

//	SmsHostSetDbgLogMask(~0);
	////////////////////////////////////////////////////
	//
	// Detect installed devices

	UINT32 ActNum;
	printf( "Getting available devices list...\n" );
	err = SmsHostApiGetDevicesList(MAX_DEVICES,	&ActNum, g_DeviceDataArr);

	if (err != SMSHOSTLIB_ERR_OK) {
		printf("SmsHostApiGetDevicesList failed, err=%d\n", err);
		goto exitapp;
	}
	if (ActNum == 0) {
		printf("Error: no SMS devices found\n");
		goto exitapp;
	}

	printf("Found %d devices.\n", ActNum );
	//////////////////////////////////////////////////////
	//
	// Initialize the first device on the list (cmmb as default)

	if (g_DeviceDataArr[0].DeviceMode == SMSHOSTLIB_DEVMD_NONE)
		g_DeviceDataArr[0].DeviceMode = SMSHOSTLIB_DEVMD_CMMB;
	printf( "Initializing device %s mode %d...\n", 
		g_DeviceDataArr[0].DeviceName , g_DeviceDataArr[0].DeviceMode );
	err = SmsHostApiDeviceInit_Req(
				g_DeviceDataArr[0].DeviceName, 
				g_DeviceDataArr[0].DeviceMode,
				12000000,
				(void*)0,
                                &LocalDevHdl);

	if (err != SMSHOSTLIB_ERR_OK) {
		printf("SmsHostApiDeviceInit_Req failed, err %#x\n", err);
		goto exitapp;
	}

	//////////////////////////////////////////////////////
	//
	// Wait for the init device response to arrive

	err = WaitArrival( 4000, SMSHOSTLIB_MSG_INIT_DEVICE_RES );
	if ( err != SMSHOSTLIB_ERR_OK )
	{
		printf ("Error initializing device - code %#x\n", err );
		goto exitapp;
	}
	
	
	//////////////////////////////////////////////////////
	//
	// Display the device firmware version 
	err = SmsHostApiGetVersion_Req( LocalDevHdl );
	if (err != SMSHOSTLIB_ERR_OK) {
		printf("SmsHostApiGetVersion_Req failed, err %#x\n", err);
		goto exitapp;
	}

	//////////////////////////////////////////////////////
	//
	// Wait for the get version response to arrive
	err = WaitArrival( 4000, SMSHOSTLIB_MSG_GET_VERSION_RES );
	if ( err != SMSHOSTLIB_ERR_OK )
	{
		printf ("Error getting  device version - code %#x\n", err );
		goto exitapp;
	}

	printf( "Device version: %s\n", g_VersionString );

// 	//////////////////////////////////////////////////////
// 	//
// 	// Tune to a frequency 
// 
// 	printf("Tuning to frequency %d ...\n", Freq );
// 
// 	err = SmsHostApiTune_Req(	LocalDevHdl, 
// 								Freq,
// 								BW_8_MHZ );
//     
// 	WaitArrival( 4000);
// 	if ( g_LastMsgType != SMSHOSTLIB_MSG_TUNE_RES || g_LastMsgErrCode != SMSHOSTLIB_ERR_OK )
// 	{
// 		printf ("Tune Error %#x\n", g_LastMsgErrCode);
// 		goto exitapp;
// 	}

	//////////////////////////////////////////////////////
	//
	// Frequency scan

	SMSHOSTLIB_SCAN_RANGE_ST ScanRange;
	ScanRange.BottomFreq = 474000000;
	ScanRange.Gap = 8000000;
	ScanRange.UpFreq = 800000000;

	printf("Scanning UHF - from %d KHz to %d KHz in %d KHz intervals...\n", 
				ScanRange.BottomFreq/1000, 
				ScanRange.UpFreq/1000, 
				ScanRange.Gap/1000 );

	g_FoundGoodFreq = FALSE;
	err = SmsHostApiScanStart_Req(	LocalDevHdl, 
									CLEAN_PREV_DB_AT_SCAN_START, 
									BW_8_MHZ, 
									SCAN_PARAM_RANGE, 
									&ScanRange );

	err = WaitArrival( 4000, SMSHOSTLIB_MSG_SCAN_START_RES );
	if ( err != SMSHOSTLIB_ERR_OK )
	{
		printf ("Scan start Error - code %#x\n", err );
		goto exitapp;
	}

	// Wait 20 seconds for the scan to finish
	err = WaitArrival( 20000, SMSHOSTLIB_SCAN_COMPLETE_IND );

	if ( !g_FoundGoodFreq )
	{
		printf ("Scan did not find any good frequencies.\n");
		goto exitapp;
	}
	else
	{
		printf ("Scan found a good frequency.\n" );
	}

	//////////////////////////////////////////////////////
	//
	// Get available networks 
	printf("Get available networks...\n");
	g_DidMsgArrive = FALSE;
	err = SmsHostApiCmmbGetAvailableNetworks_Req( LocalDevHdl, MAX_NETWORKS, &NumNetworks, g_NetworksInfoArr );
	
	err = WaitArrival( 4000, SMSHOSTLIB_MSG_CMMB_GET_AVAIL_NETWORKS_RES );
	if ( err != SMSHOSTLIB_ERR_OK )
	{
		printf ("Error getting networks info - code %#x\n", err );
		goto exitapp;
	}
	
	if ( NumNetworks == 0 )
	{
		printf ("No networks available. Aborting.\n");
		goto exitapp;
	}

	printf ( "List of available networks:\n" );
	UINT32 i;
	for ( i=0 ; i < NumNetworks ; i++ )
	{
		printf( "%d. Level %d, Number %d, Name %s\n",
				i,
				g_NetworksInfoArr[i].NetworkLevel,
				g_NetworksInfoArr[i].NetworkNumber,
				g_NetworksInfoArr[i].Name );
	}
	printf("\n");

	//////////////////////////////////////////////////////
	//
	// Start capturing control info for the first network

	printf("Starting control info on network %d/%d ...\n", 
				g_NetworksInfoArr[0].NetworkLevel,
				g_NetworksInfoArr[0].NetworkNumber );
	
	err = SmsHostApiCmmbStartControlInfo_Req(	LocalDevHdl, 
												g_NetworksInfoArr[0].NetworkLevel,
												g_NetworksInfoArr[0].NetworkNumber,
												&g_ControlInfoServiceHandle );

	err = WaitArrival( 4000, SMSHOSTLIB_MSG_CMMB_START_CONTROL_INFO_RES );
	if ( err != SMSHOSTLIB_ERR_OK )
	{
		printf ("Error starting control info - code %#x\n", err );
		goto exitapp;
	}
	
	printf("Started capturing control info to file sms_multiplex_capture.mfs. Channel data is marked with a '+'. \n");
	
	//////////////////////////////////////////////////////
	//
	// Start capturing a service 
	printf("Start service %#x (lev/num %d/%d)...\n", 
		STREAM_SERVICE_ID_TO_START,
		g_NetworksInfoArr[0].NetworkLevel,
		g_NetworksInfoArr[0].NetworkNumber );
	
	err = SmsHostApiCmmbStartService_Req(	LocalDevHdl, 
						g_NetworksInfoArr[0].NetworkLevel,
						g_NetworksInfoArr[0].NetworkNumber,
			  			STREAM_SERVICE_ID_TO_START,
			 			&g_StartedServiceHandle );

	//WaitForSingleObject(g_MsgArrivedEvent, 4000);
	err = WaitArrival( 4000, SMSHOSTLIB_MSG_CMMB_START_SERVICE_RES );
	if ( err != SMSHOSTLIB_ERR_OK )
	{
		printf ("Error starting a service  - code %#x\n", err );
		goto exitapp;
	}		

	printf("Started capturing a service to file sms_service_capture.bin . Service data is marked with a '*'. \n");

exitapp:
	printf( "Press <enter> to finish...\n");

	getc( stdin );
	
	if ( g_StartedServiceHandle != 0 )
	{
		printf ("Stopping service...\n" );
		err = SmsHostApiCmmbStopService_Req(	LocalDevHdl, 
												g_StartedServiceHandle );

		//WaitForSingleObject(g_MsgArrivedEvent, 4000);
		err = WaitArrival( 4000, SMSHOSTLIB_MSG_CMMB_STOP_SERVICE_RES );
		if ( err != SMSHOSTLIB_ERR_OK )
		{
			printf ("Error stopping service - code %#x\n", err );
		}		
		g_StartedServiceHandle = 0;
	}

	if ( g_ControlInfoServiceHandle != 0 )
	{
		printf ("Stopping control info...\n" );
		err = SmsHostApiCmmbStopControlInfo_Req( LocalDevHdl );		// Control information is on channel 

		err = WaitArrival( 4000, SMSHOSTLIB_MSG_CMMB_STOP_CONTROL_INFO_RES );
		if ( err != SMSHOSTLIB_ERR_OK )
		{
			printf ("Error stopping control info - code %#x\n", err );
		}		
		g_ControlInfoServiceHandle = 0;
	}

	printf( "\n" );
	
	g_IsTerminated = TRUE;
	fclose( g_MultipklexFp );
	fclose( g_ServiceFp );

	if (LocalDevHdl != (SmsHostApiDeviceHandle)~0)
	{
 		SmsHostApiDeviceTerminate_Req( LocalDevHdl );
	}
	SmsHostApiLibTerminate();
	
	printf( "CmmbDemoApp Finished.\n" );

	return 0;
}
//*******************************************************************************
// 
void CmmbPrintStatistics( SMSHOSTLIB_STATISTICS_CMMB_ST* pStats )
{
	UINT32 i;
	// Print the global statistics
	printf( "SNR %u, RSSI %d, ErrorsCounter %d, IsDemodLocked %d ",
		pStats->SNR>>16,
		pStats->RSSI,					
		pStats->ErrorsCounter,
		pStats->IsDemodLocked );
	printf( "InBandPwr %d, CarrierOffset %d, Frequency %d", 		
		pStats->InBandPwr,				
		pStats->CarrierOffset,			
		pStats->Frequency );

	// Print each channel's statistics
	for ( i = 0 ; i < pStats->NumActiveChannels && i < SMSHOSTLIB_CMMB_MAX_STATS_NUM_CHANNELS ; i++ )
	{
		SMSHOSTLIB_CMMB_CHANNEL_STATS_ST* pChStats = &pStats->ChannelsStatsArr[i];
		printf( "Multiplex ID %d: Total LDPC W %d LDPC not converged %d RS total %d RS Bad %d\n"
				"		Post LDPC bad bytes %d Good frame headers %d Bad frame headers %d\n",
			i,
			pChStats->Id,
			pChStats->LdpcWordsCount,
			pChStats->LdpcNonConvergedWordsCount,
			pChStats->LdpcCycleCountAvg,
			pChStats->RsNumTotalRows,
			pChStats->RsNumBadRows,
			pChStats->PostLdpcBadBytes,
			pChStats->NumGoodFrameHeaders,
			pChStats->NumBadFrameHeaders );
	}
	if ( pStats->ErrorsCounter > 0 )
	{
		printf( "Error counter is not 0! This indicates a firmware or a host-chip interface problem.\n" );
		printf( "Last errors' IDs: " );
		for ( i = 0 ; i < SMSHOSTLIB_CMMB_STATS_ERR_HISTORY_LEN ; i++ )
		{
			printf( "%d, ", pStats->ErrorsHistory[i] );
		}
		printf("\n");
	}
}

//////////////////////////////////////////////////////
//
// Control callback - handles API responses
//
void CtrlCallback(	void*						ClientContext,	//!< Context of client
					SMSHOSTLIB_MSG_TYPE_RES_E	MsgType,		//!< Response type	
					SMSHOSTLIB_ERR_CODES_E		ErrCode,		//!< Response success code
					void* 						pPayload,		//!< Response payload
					UINT32						PayloadLen)		//!< Response payload length
{
	if ( g_IsTerminated )
	{
		return;
	}   
	
	switch( MsgType )
	{
	case SMSHOSTLIB_MSG_GET_VERSION_RES:
		{
			UINT32 SizeToCopy = sizeof( g_VersionString );
			if ( SizeToCopy >  PayloadLen )
			{
				SizeToCopy = PayloadLen;
			}
			memcpy( g_VersionString, pPayload, SizeToCopy );
		}
		break;
	case SMSHOSTLIB_SCAN_PROGRESS_IND:
	case SMSHOSTLIB_SCAN_COMPLETE_IND:
		{
			UINT32 Freq = *(UINT32*)pPayload;
			BOOL IsGoodFreq = (ErrCode == SMSHOSTLIB_ERR_OK) ;
			printf ( "%s Scan progress. Frequency %d KHz, %s\n", 
						(IsGoodFreq)?"***":"---",
						Freq/1000,
						(IsGoodFreq)?"******* LOCK *******":"no CMMB signal." );
			if ( IsGoodFreq )
			{
				g_FoundGoodFreq = TRUE;
			}
		}
		break;
	case SMSHOSTLIB_MSG_GET_STATISTICS_EX_RES:

		CmmbPrintStatistics( (SMSHOSTLIB_STATISTICS_CMMB_ST*)pPayload);
	break;

	default:
		break;
	}
	
	if ( g_WaitingForType == MsgType )
	{
		g_WaitedErrCode = ErrCode;
		g_DidMsgArrive = TRUE;
	}
		
}

//////////////////////////////////////////////////////
//
// Data callback - handles data (control info, services)
//
void DataCallback(void*		ClientPtr, 
				  UINT32	ServiceHandle, 
				  UINT8*	pBuffer, 
				  UINT32	BufferSize )
{
	if ( g_IsTerminated )
	{
		return;
	}   
	
	//printf( "Data: Handle %d, size %d\n", ServiceHandle, BufferSize );
	if ( ServiceHandle == g_ControlInfoServiceHandle )
	{
		// All strated channels go to service handle 1
		g_MpxCapturedSize += BufferSize;

		fwrite(pBuffer, BufferSize, 1, g_MultipklexFp);
		//printf("Storing multiplex info... (%d bytes)\n", g_MpxCapturedSize);
		printf( "+" );
	} 
	else
	{
		// All strated channels go to service handle 1
		g_ServiceCapturedSize += BufferSize;

		fwrite(pBuffer, BufferSize, 1, g_ServiceFp);
		//printf("Storing service info... (%d bytes)\n", g_ServiceCapturedSize);
		printf( "*" );
	}
	fflush( stdout );
}
